home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / FORWARD.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-09-14  |  63.3 KB  |  2,420 lines

  1. /* Some of the code in this file was originally based on the following file:
  2.  * gateway.c : Paul Healy, EI9GL, 900818
  3.  *
  4.  * Rewrote forwarding mechanism to use "X-Forwarded-To" paradigm instead of
  5.  * "X-BBS-To", added timer support, etc.  Anders Klemets, SM0RGV, 901009.
  6.  */
  7. /* Mods by G1EMM and WG7J */
  8. #include "global.h"
  9. #include "files.h"
  10. #include "ctype.h"
  11. #include "commands.h"
  12. #ifndef MSDOS
  13. #include <time.h>
  14. #include "ftp.h"
  15. #endif
  16. #include "bm.h"
  17. #include "usock.h"
  18.  
  19. #if !defined(_lint)
  20. static char rcsid[] OPTIONAL = "$Id: forward.c,v 1.49 1997/09/14 14:37:46 root Exp root $";
  21. #endif
  22.  
  23. #ifdef MBFWD
  24.  
  25. extern int MbForwarded, SYSOPprotect;
  26. extern char *mbxRCall;
  27. extern char AXRosecall[AXALEN];
  28.  
  29. #ifdef XFWD
  30. extern int MXfwd;
  31. #endif
  32.  
  33. #ifdef FBBFWD
  34. extern int Mfbb;
  35. #endif
  36.  
  37. #ifdef LOCK
  38. extern int Kblocked;
  39. #endif
  40.  
  41. extern int BBSdump;
  42. extern int MbBID, MbMID;
  43.  
  44. #define ISPROMPT(s) (strlen(s) > 1 && s[strlen(s)-2] == '>')
  45. static struct timer fwdtimer;
  46. static int lastSessionSkipped;
  47. extern int FWDmode, FWDpersonal, FWDbulletins, FWDreverse, FWDinreverse;
  48. extern int FWDctlz;
  49. extern char FWDCall[AXALEN];
  50.  
  51. extern char *Mbhaddress;
  52. extern int MbRSTYLE;
  53. extern char *Mbfwdinfo;
  54. extern char *Mbqth;
  55. extern char *Mbzip;
  56. extern int Mbsmtptoo;
  57. extern int UtcOffset;
  58. extern int MBXMaint;
  59. extern int MBXMaintMode;
  60.  
  61. struct subchan *subchannels;
  62.  
  63. #if defined(FBBCMP) && defined(UNIX)
  64. extern int Mfbbcmp;
  65. #endif
  66.  
  67. #ifdef STRICT_CALL
  68. extern int PBBSstrict;
  69. #endif
  70.  
  71. static void sendtempfile (FILE * newfile, struct mbx * m, int sendit);
  72.  
  73. static int uselessconnect (struct mbx * m, char *filename);
  74. static void sendwithcorrectNL (struct mbx * m, char *str);
  75. void checkforALTs (void);
  76. static void checkoneALT (char *name);
  77. extern void updateFwd (char *who, char *area, long bid, long size);
  78. extern void ReadFwdBbs (void);
  79. extern void freeareas (void);
  80. void forwardingSummary (void);
  81. static char *findident (char *str, int n, char *result);
  82. char *mbxtime (char *line);
  83. static int fwdanybbs (struct mbx * m, int *poll, int *theindex);
  84. static void fwdtick (void *v);
  85. void fwdproc (int, void *, void *);
  86. static int isconnbbs (struct mbx * m);
  87. static void startfwd (int a, void *v1, void *v2);
  88. static int openconn (int argc, char *argv[], void *p);
  89. static int sendmsgtobbs (struct mbx * m, int msgn, char const *dest, int bulletin);
  90. static char *grabtext (char *from, char *to, int marker, int maxlen);
  91. extern char *nntp_name_expansion (char *name);
  92. extern void bid_delete (register char *string);
  93. int forwardreset (int argc, char *argv[], void *p);
  94. static int checkone (char *line, const char *str, const char *sub);
  95. static int adaptaddress (char *line);
  96. static int fwdthisarea (struct mbx * m, FILE * fwd, char *area, char *newto);
  97. static void fwdcleanup (struct mbx * m, const char *string);
  98. static int fwd_clockset (struct mbx * m);
  99. extern int indexFwdBbs (char *name);
  100. extern int makeBBSbid (char *bid, int bidlen, char *line);
  101. extern void bid_add (char *bid, time_t now, int tofile, char *to);
  102. extern int msgidcheck (char *string);
  103.  
  104.  
  105. #ifdef CATALOG
  106. #include "catalog.h"
  107.  
  108. #define CAT forward_catalog
  109.  
  110. #define forwardingtimer    __STR(0)
  111. #define nostart        __STR(1)
  112. #define defering    __STR(2)
  113. #define queueing    __STR(3)
  114. #define delayedmaintenance __STR(4)
  115. #define started        __STR(5)
  116. #define unabletostart    __STR(6)
  117. #define examining    __STR(7)
  118. #define alreadyconnected __STR(8)
  119. #define checkingforfile    __STR(9)
  120. #define forwardingcomplete __STR(10)
  121. #define connectionfailed __STR(11)
  122. #define scriptdone    __STR(12)
  123. #define waitingfor    __STR(13)
  124. #define Netromunavailable __STR(14)
  125. #define Netromsocket    __STR(15)
  126. #define mailsent    __STR(16)
  127. #define mailrefused    __STR(17)
  128. #define unexpectedresponse __STR(18)
  129. #define forwardingmailto __STR(19)
  130. #define forwardfailed    __STR(20)
  131. #define badax25iface    __STR(21)
  132. #define nosidfound    __STR(22)
  133. #define nosidfound2    __STR(23)
  134.  
  135. #else /* CATALOG */
  136. static const char forwardingtimer[] = "Forwarding timer: %lu/%lu\n";
  137. static const char nostart[] = "Couldn't start Forwarding process";
  138. static const char defering[] = "fwd: Deferring large message to %s, allowed=%ld, size=%ld\n";
  139. static const char queueing[] = "fwd: queueing message %ld from BBS %s, to alternate: %s\n";
  140. static const char delayedmaintenance[] = "fwd: forward delayed - maintenance mode\n";
  141. static const char started[] = "fwd: forward started\n";
  142. static const char unabletostart[] = "fwd: unable to start new maibox\n";
  143. static const char examining[] = "fwd: examining '%s'\n";
  144. static const char alreadyconnected[] = "fwd: '%s' already connected\n";
  145. static const char checkingforfile[] = "fwd: checking for file '%s'\n";
  146. static const char forwardingcomplete[] = "PBBS forwarding complete to: %s\n";
  147. static const char connectionfailed[] = "fwd: Connection failed to %s, TRY = %d\n";
  148. static const char scriptdone[] = "fwd: %s, script done\n";
  149. static const char waitingfor[] = "fwd: %s, wait %ld -  waiting for %s\n";
  150. static const char Netromunavailable[] = "fwd: Netrom route unavailable - %s\n";
  151. static const char Netromsocket[] = "fwd: unable to open Netrom socket - %s\n";
  152. static const char mailsent[] = "PBBS mail sent: %s ";
  153. static const char mailrefused[] = "PBBS mail refused: %s\n     %s";
  154. static const char unexpectedresponse[] = "PBBS mail - unexpected response: %s\n     %s";
  155. static const char forwardingmailto[] = "PBBS %sforwarding mail to: %s ";
  156. static const char forwardfailed[] = "PBBS forward failed: %s errno %d";
  157. static const char badax25iface[] = "Invalid forwarding interface '%s' for %s";
  158. static const char nosidfound[] = "No SID received from remote system %s - aborting";
  159. static const char nosidfound2[] = "'No SID' indicates a probable problem with your forwarding script";
  160. #endif /* CATALOG */
  161.  
  162.  
  163.  
  164. #ifdef FBBFWD
  165. static char *ltoa (long value, char *string, int radix OPTIONAL);
  166.  
  167. static char *
  168. ltoa (long value, char *string, int radix OPTIONAL)
  169. {
  170.     /* assume radix of 10, since only called with that value */
  171.     sprintf (string, "%ld", value);
  172.     return (string);
  173. }
  174. #endif
  175.  
  176.  
  177.  
  178. char *
  179. fwd_bbsname (struct mbx *m)
  180. {
  181. static char tmp[20];
  182.  
  183.     if (*m->call)
  184.         (void) pax25 (tmp, m->call);
  185.     else {
  186.         strncpy (tmp, m->name, 19);
  187.         (void) strupr (tmp);
  188.     }
  189.     return (tmp);
  190. }
  191.  
  192.  
  193.  
  194. /***************************************************************************
  195.    findident copies the 'n'th alphanumeric sequence from 'str' to result.
  196.    It returns a ptr to result. It returns "\0" for missing identifier etc.
  197.    Uses isalnum macro to decide on alphanumeric/non-alnum status.
  198. */
  199. static char *
  200. findident (char *str, int n, char *result)
  201. {
  202. int count;        /* current identifier */
  203.  
  204.     count = 0;
  205.     *result = '\0';
  206.     while ((count < n) && (*str != '\0')) {    /* Process alnum or non alnum seq */
  207.         while ((*str != '\0') && (!isalnum (*str)))    /* Get rid of ';:.@%"# etc */
  208.             str++;
  209.         if ((*str != '\0') && isalnum (*str)) {    /* this is an alnum seq */
  210.             count++;
  211.             while ((*str != '\0') && (isalnum (*str) || (*str == '_')))
  212.                 if (count == n)
  213.                     *result++ = *str++;
  214.                 else
  215.                     str++;
  216.             if (count == n)
  217.                 *result = '\0';
  218.         }
  219.     }
  220.     return result;
  221. }
  222.  
  223.  
  224. extern int Mbfullsvc;
  225.  
  226.  
  227.  
  228. static int
  229. checkone (char *line, const char *str, const char *sub)
  230. {
  231. char *cp;
  232.  
  233.     if (str && line && !strnicmp (line, str, strlen (str)) && (cp = strstr (line, Hostname)) != NULLCHAR) {
  234.         strcpy (cp, sub);
  235.         return 1;
  236.     }
  237.     return 0;
  238. }
  239.  
  240.  
  241.  
  242. static int
  243. adaptaddress (char *line)
  244. {
  245. char buf[60], *cp;
  246.  
  247.     (void) pax25 (buf, Mycall);
  248.     if ((cp = strpbrk (buf, DIGI_IDS)) != NULLCHAR)
  249.         *cp = '\0';    /* remove SSID */
  250.     if (Mbhaddress != NULLCHAR) {
  251.         strcat (buf, ".");
  252.         strcat (buf, Mbhaddress);
  253.     }
  254.     strcat (buf, "\n");
  255.     if (checkone (line, Hdrs[XMAILGROUP], buf))
  256.         return 1;
  257.     if (checkone (line, Hdrs[ERRORSTO], buf))
  258.         return 1;
  259.     return (checkone (line, Hdrs[REPLYTO], buf));
  260. }
  261.  
  262.  
  263.  
  264. static void
  265. sendwithcorrectNL (struct mbx *m, char *str)
  266. {
  267. #if defined(UNIX) && defined(FBBCMP)
  268.     if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP) {
  269.         rip (str);
  270.         strcat (str, "\r\n");
  271.     }
  272. #endif
  273.     fputs (str, m->quickfile);
  274. }
  275.  
  276.  
  277.  
  278. /**************************************************************************/
  279. /* sendmsg() modified to send the R: line always.
  280.  * also added some additional strings like qth and zipcode etc. to R: line.
  281.  * Original SMTP headers get forwarded optionally.
  282.  * 920114 - WG7J
  283.  */
  284.  
  285. void
  286. sendmsg (struct mbx *m, int msgn, char *thebid)
  287. {
  288. FILE *oldfile, *newfile;
  289. char buf[LINELEN], tb[LINELEN], *cp;
  290. char Rline[LINELEN];
  291. int rec = 0;        /* rec is line-counter */
  292. unsigned int msgid = 0;    /* message id number - WG7J */
  293. int col, ccnt;
  294. char c;
  295. int sendthefile = 0;
  296. long endofmsg = 0L;
  297.  
  298.     /* point to start and end of this message in file */
  299.     fseek (m->mfile, m->mbox[msgn].start, 0);
  300.     if (m->nmsgs > msgn)
  301.         endofmsg = m->mbox[msgn + 1].start;
  302.  
  303.     /* If the data part of the message starts with "R:" the RFC-822
  304.      * headers will not normally be forwarded. Instead we will add an R:
  305.      * line of our own. ALWAYS forward with "R:" line
  306.      */
  307.  
  308.     /* This loop is until we have read our internal MID */
  309.     for (;;) {
  310.         /* read a line */
  311.         if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR)
  312.             break;
  313.         kwait (NULL);
  314.  
  315.         if (rec == 1) {    /* We are on the line with the MID */
  316.             /* look at the line following Received:
  317.              * This has the ID followed by ' ; date&time in arpa-format'
  318.              * Get the message number from the ID line - WG7J
  319.              */
  320.             if ((cp = strstr (buf, "AA")) != NULLCHAR)
  321.                 /* what follows is the message-number */
  322.                 msgid = (unsigned int) atoi (cp + 2);
  323.  
  324.             /* get the ARPA format date/time string */
  325.             if ((cp = strchr (buf, ';')) != NULLCHAR)
  326.                 strncpy (tb, cp + 1, LINELEN);    /* point to the date of receipt */
  327.  
  328.             /* Get the callsign for the R: line */
  329.             if (mbxRCall)
  330.                 strncpy (buf, mbxRCall, LINELEN);
  331.             else
  332.                 (void) pax25 (buf, Mycall);
  333.             if ((cp = strpbrk (buf, DIGI_IDS)) != NULLCHAR)
  334.                 *cp = '\0';    /* remove SSID */
  335.  
  336.             /* If not a fullservice BBS, don't send the R: line */
  337.             if (Mbfullsvc) {
  338.                 if (!MbRSTYLE) {
  339.                     sprintf (Rline, "R:%s @:%s%s%s ", mbxtime (tb), buf,
  340.                     (Mbhaddress != NULLCHAR) ? "." : "",
  341.                          (Mbhaddress != NULLCHAR) ? Mbhaddress : "");
  342.                     if (Mbfwdinfo)
  343.                         sprintf (&Rline[strlen (Rline)], "[%s] ", Mbfwdinfo);
  344.                     if (Mbqth)
  345.                         sprintf (&Rline[strlen (Rline)], "%s ", Mbqth);
  346.                     if (MbMID)
  347.                         sprintf (&Rline[strlen (Rline)], "#:%u ", msgid);
  348.                     if (Mbzip)
  349.                         sprintf (&Rline[strlen (Rline)], "Z:%s ", Mbzip);
  350.                     if (MbBID)
  351.                         sprintf (&Rline[strlen (Rline)], "$:%s", thebid);
  352.                     strcat (Rline, "\n");
  353.                 } else
  354.                     sprintf (Rline, "R:%s %d@%s%s%s\n", mbxtime (tb), msgid, buf,
  355.                          (Mbhaddress) ? "." : "", (Mbhaddress) ? Mbhaddress : "");
  356. #ifdef BBSEXPORT
  357.                 if (m->quickfile)
  358.                     sendwithcorrectNL (m, Rline);
  359.                 else
  360. #endif
  361.                     usputs (m->user, Rline);
  362.             }    /* Mbfullsvc */
  363.             break;    /* done with this portion of the message */
  364.         }        /* rec == 1 */
  365.         /* The first Received: line is the one that we have added */
  366.         if (!rec && htype (buf) == RECEIVED)
  367.             ++rec;
  368.     }
  369.  
  370.  
  371.     /* Go past the SMTP headers to the data of the message.
  372.      * Check if we need to forward the SMTP headers! 920114 - WG7J
  373.      */
  374.  
  375.  
  376.     /* first, save any current quickfile, and replace it with a tmpfile
  377.      * for placing any smtp headers into.
  378.      */
  379.     oldfile = m->quickfile;
  380.     newfile = tmpfile ();
  381.     m->quickfile = newfile;
  382.  
  383.     /* place the separating NL */
  384. #if defined(UNIX) && defined(FBBCMP)
  385.     if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP)
  386.         fputs ("\r\n", m->quickfile);
  387.     else
  388. #endif
  389.         fputs ("\n", m->quickfile);
  390.  
  391.  
  392.     /* This loop is to process the RFC headers and send any needed ones
  393.      * to a TEMP file, to be inserted at the proper time.
  394.      */
  395.     for (;;) {
  396.         if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR)
  397.             break;
  398.         kwait (NULL);
  399.         if (*buf == '\n')    /* last header line */
  400.             break;
  401.         if (adaptaddress (buf)) {    /* check for headers always sent */
  402.             sendwithcorrectNL (m, buf);
  403.             sendthefile = 1;
  404.         } else if (Mbsmtptoo) {
  405.             /* YES, forward SMTP headers TOO !*/
  406.             switch (htype (buf)) {
  407.                 case XFORWARD:    /* Do not forward the "X-Forwarded-To:" lines */
  408.                 case STATUS:    /* Don't forward the "Status:" line either */
  409.                 case BBSTYPE:
  410.                 case SUBJECT:
  411.                 case TO:
  412.                 case DATE:
  413.                     /* never send these headers */
  414.                     break;
  415.                 case FROM:    /* Don't forward the "From: " line either, make it ">From: " */
  416.                     cp = strdup (buf);
  417.                     strcpy (buf, ">");
  418.                     strcat (buf, cp);
  419.                     free (cp);
  420.                     /* note fall-through */
  421.                 default:
  422.                     trimrightCR (buf);
  423.                     sendwithcorrectNL (m, buf);
  424.                     sendthefile = 1;
  425.             }    /* switch */
  426.         }        /* Mbsmtptoo */
  427.     }            /* for */
  428.  
  429.     /* Now reset the quickfile to it's previous state and rewind tempfile */
  430.     m->quickfile = oldfile;
  431.     if (newfile)
  432.         rewind (newfile);
  433.  
  434.     /* If there are other R: headers, process them first */
  435.     for (;;) {        /* do this while you have R: lines */
  436.         /* if there is no data, send the tempfile and you're done */
  437.         if (fgets (buf, sizeof (buf), m->mfile) == NULLCHAR) {
  438.             sendtempfile (newfile, m, sendthefile);
  439.             return;    /* NO text ??? */
  440.         }
  441.         if (strncmp (buf, "R:", 2))    /* No more R: lines! */
  442.             break;
  443. #ifdef BBSEXPORT
  444.         if (m->quickfile)
  445.             sendwithcorrectNL (m, buf);
  446.         else
  447. #endif
  448.             usputs (m->user, buf);
  449.     }
  450.  
  451.     /* Now add the smtp headers desired. */
  452.     sendtempfile (newfile, m, sendthefile);
  453.  
  454.     if (!strncmp (Hdrs[RRECEIPT], buf, strlen (Hdrs[RRECEIPT]))) {    /* return receipt line */
  455.         if (!isarea (m->area)) {    /* only send if not a bulletin */
  456. #ifdef BBSEXPORT
  457.             if (m->quickfile)
  458.                 sendwithcorrectNL (m, buf);
  459.             else
  460. #endif
  461.                 usputs (m->user, buf);
  462.         }
  463.         (void) fgets (buf, sizeof (buf), m->mfile);    /* eat the blank line following */
  464.         if (*buf == '\n')
  465.             (void) fgets (buf, sizeof (buf), m->mfile);    /* eat the blank line following */
  466.     }
  467.     /* place the separating NL */
  468. #ifdef BBSEXPORT
  469. #if defined(UNIX) && defined(FBBCMP)
  470.     if (m->quickfile) {
  471.         if (m->msglst && Mfbbcmp && m->sid & MBX_FBBCMP)
  472.             fputs ("\r\n", m->quickfile);
  473.         else
  474. #else
  475.     if (m->quickfile) {
  476. #endif
  477.             fputs ("\n", m->quickfile);
  478.     } else
  479. #endif
  480.         usputs (m->user, "\n");
  481.  
  482.     /* we now have the first data line in buf, so send it */
  483. #ifdef BBSEXPORT
  484.     if (m->quickfile)
  485.         sendwithcorrectNL (m, buf);
  486.     else
  487. #endif
  488.         usputs (m->user, buf);
  489.  
  490.  
  491.  
  492.     /* the rest of the message is treated below */
  493.     col = 0;
  494.     while (!feof (m->mfile)) {
  495.         if (endofmsg && (ftell (m->mfile) >= endofmsg))
  496.             break;
  497.         for (col = 0; col < MAXBUF;) {
  498.             c = (char) getc (m->mfile);
  499.             if (feof (m->mfile))    /* end this line */
  500.                 break;
  501.             if (c == '\t') {
  502.                 ccnt = col + 8 - (col & 7);
  503.                 if (ccnt >= MAXBUF)    /* end this line */
  504.                     break;
  505.                 while (col < ccnt)
  506.                     buf[col++] = ' ';
  507.             } else {
  508.                 if (c == '\n')
  509.                     break;
  510.                 buf[col++] = c;
  511.             }
  512.         }        /* for */
  513.         if (col < MAXBUF)
  514.             buf[col++] = '\n';
  515.         buf[col] = '\0';
  516.  
  517.         if (!strncmp (buf, "From ", 5))    /* somehow endofmsg didn't work */
  518.             break;
  519. #ifdef BBSEXPORT
  520.         if (m->quickfile)
  521.             sendwithcorrectNL (m, buf);
  522.         else
  523. #endif
  524.             usputs (m->user, buf);
  525.         kwait (NULL);
  526.     }            /* while */
  527. }
  528.  
  529.  
  530.  
  531. static void
  532. sendtempfile (FILE *newfile, struct mbx *m, int sendit)
  533. {
  534. int c;
  535.  
  536.     if (sendit) {
  537. #ifdef BBSEXPORT
  538.         if (m->quickfile) {
  539.             while ((c = getc (newfile)) != EOF)
  540.                 fputc (c, m->quickfile);
  541.         } else
  542. #endif
  543.             (void) sendfile (newfile, m->user, ASCII_TYPE, 0);
  544.     }
  545.     (void) fclose (newfile);
  546. }
  547.  
  548.  
  549.  
  550. /* Parse a line for date and time in Arpanet format
  551.  * (Day, day Month year hh:mm:ss Zone) and return it in mailbox format
  552.  * (yymmdd/hhmmz)
  553.  */
  554. char *
  555. mbxtime (char *line)
  556. {
  557. static char buf[13];
  558. char *cp;
  559. int year, month, day, hour, minute, maxdays;
  560.  
  561.     cp = line;
  562.     if (!cp)
  563.         return NULLCHAR;
  564.     while (isspace (*cp))    /* skip initial blanks */
  565.         ++cp;
  566.     if (*cp == '\0')
  567.         return NULLCHAR;
  568.     if (strlen (cp) < 22)
  569.         return NULLCHAR;
  570.     cp += 5;
  571.     day = atoi (cp);
  572.     if (*(++cp) != ' ')
  573.         ++cp;
  574.     ++cp;
  575.     for (month = 0; month < 12; ++month)
  576.         if (strnicmp (Months[month], cp, 3) == 0)
  577.             break;
  578.     if (month == 12)
  579.         return NULLCHAR;
  580.  
  581.     /* Get things, and adjust for GMT/UTC time - WG7J */
  582.     month++;
  583.     year = atoi (cp + 4);
  584.     hour = atoi (cp + 7);
  585.     minute = atoi (cp + 10);
  586.  
  587.     if (UtcOffset != 0) {
  588.         hour -= UtcOffset;
  589.         /* See if we went past midnight */
  590.         if (hour > 23) {
  591.             hour -= 24;
  592.             ++day;
  593.             /*Check for next month*/
  594.             if (month == 2) {    /*February, check leap-year*/
  595.                 if ((year % 4) == 0)
  596.                     maxdays = 29;
  597.                 else
  598.                     maxdays = 28;
  599.             } else {
  600.                 if ((month % 2) == 0)
  601.                     maxdays = 30;
  602.                 else
  603.                     maxdays = 31;
  604.             }
  605.             if (day > maxdays) {    /*adjust month*/
  606.                 day = 1;
  607.                 if (++month == 13) {    /*next year*/
  608.                     month = 1;
  609.                     year++;
  610.                 }
  611.             }
  612.         } else if (hour < 0) {    /*previous day !*/
  613.             hour += 24;
  614.             if (--day == 0) {    /*previous month*/
  615.                 if (--month == 0) {    /*previous year*/
  616.                     year--;
  617.                     month = 12;
  618.                 }
  619.                 if (month == 2) {    /* February, check leap year */
  620.                     if ((year % 4) == 0)
  621.                         day = 29;
  622.                     else
  623.                         day = 28;
  624.                 } else {
  625.                     if ((month % 2) == 0)
  626.                         day = 30;
  627.                     else
  628.                         day = 31;
  629.                 }
  630.             }
  631.         }
  632.     }
  633.     sprintf (buf, "%02d%02d%02d/%02d%02dz", year, month, day, hour, minute);
  634.     return buf;
  635. }
  636.  
  637.  
  638.  
  639. static char *
  640. grabtext (char *from, char *to, int marker, int maxlen)
  641. {
  642.     while (*from != marker) {
  643.         *to++ = *from++;
  644.         if (!--maxlen)
  645.             break;
  646.     }
  647.     *to = '\0';
  648.     return from + 1;
  649. }
  650.  
  651.  
  652.  
  653. /* Makes a command line and returns -1 if the message cannot be sent and
  654.    -2 if message couldn't be sent and should be deleted.
  655.  */
  656. int
  657. makecl (m, msgn, dest, line, subj, bid, bul)
  658. struct mbx *m;
  659. int msgn;            /* Message number */
  660. char const *dest;        /* Destination address to use instead of To: line */
  661. char *line, *subj;        /* Buffers to keep command line and subject */
  662. char *bid;            /* Buffer to keep bid */
  663. int *bul;            /* True if message is in public message area */
  664. {
  665. int bulletin = *bul;
  666. int foundbid = 0;
  667. int foundmid = 0;
  668. char to[LINELEN], atbbs[LINELEN], from[LINELEN], buf[LINELEN], *cp;
  669. #ifdef FBBFWD
  670. char bid2[LINELEN];
  671. char tmp[40];
  672. #endif
  673.  
  674.     if (m->mfile == NULLFILE)
  675.         return -1;
  676.  
  677.     /* used to be if(!bulletin && (m->mbox[msgn].status & BM_READ)) */
  678.     if (!issysarea (m->area) && (m->mbox[msgn].status & BM_READ))
  679.         return -2;    /* the message was already read */
  680.     fseek (m->mfile, m->mbox[msgn].start, 0);
  681.     *bid = *to = *atbbs = *from = '\0';
  682.     if (subj != NULLCHAR)
  683.         *subj = '\0';
  684.     m->stype = bulletin ? 'B' : 'P';    /* default to SB or SP */
  685.     /* if it comes from a NTS area, always send as traffic, ie 'ST' - WG7J */
  686.     if (!strnicmp (m->area, "nts", 3))
  687.         m->stype = 'T';
  688.     while (fgets (buf, sizeof (buf), m->mfile)) {
  689.         if (buf[0] == '\n')
  690.             break;    /* envelope finished */
  691.         switch (htype (buf)) {
  692.             case TO:
  693.                 trimrightCR (buf);
  694.                 /* The following code tries to parse "To: " lines where the
  695.                  * address looks like any of the following: "to@atbbs",
  696.                  * "<to@atbbs>", "<to%atbbs@host>" and with possible spaces
  697.                  * surrounding the '<>' characters.
  698.                  */
  699.                 if ((cp = getaddress (buf, 0)) == NULLCHAR)
  700.                     break;
  701.                 strncpy (to, cp, LINELEN);
  702.                 if ((cp = strchr (to, '%')) != NULLCHAR) {    /* look for a '%' */
  703.                     strncpy (atbbs, cp + 1, LINELEN);
  704.                     *cp = '\0';    /* "to" ends at the '%' character */
  705.                     if ((cp = strchr (atbbs, '@')) != NULLCHAR)
  706.                         *cp = 0;
  707.                 } else {    /* no '%' but maybe a '@'? */
  708.                     if ((cp = strchr (to, '@')) != NULLCHAR) {
  709.                         strncpy (atbbs, cp + 1, LINELEN);
  710.                         *cp = '\0';    /* "to" ends at the '@' character */
  711.                     }
  712.                 }
  713.  
  714.                 /* "to" or "atbbs" should not be more than 6 characters (ALEN).
  715.                  * If "to" is too long, it might simply be because the area name
  716.                  * is longer than 6 characters, but it might also be because
  717.                  * the address on the To: line is in an obscure format that we
  718.                  * failed to parse (eg '!' character notation.)
  719.                  */
  720.                 if (strlen (to) > ALEN) {
  721. #if 0
  722.                     /* Play safe and set "to" and "atbbs" to the area name */
  723.                     strncpy (to, m->area, LINELEN);
  724.                     strncpy (atbbs, m->area, LINELEN);
  725. #else
  726.                     /* if "to" or "atbbs" are > 6 character, they are IMPROPER. Delete them */
  727.                     return -2;
  728. #endif
  729.                 }
  730.                 /* why would we want to add an atbbs if the message doesn't have one originally ?!?! */
  731. #if 0
  732.                 if (*atbbs == '\0')
  733.                     strncpy (atbbs, to, LINELEN);
  734. #endif
  735.  
  736.                 to[ALEN] = '\0';
  737.                 /* Only if the BBS supports "hierarchical routing designators"
  738.                  * is the atbbs field allowd to be longer than 6 characters and
  739.                  * have dots in it.
  740.                  */
  741.                 if ((m->sid & MBX_HIER_SID) == 0) {
  742.                     atbbs[ALEN] = '\0';    /* 6 character limit */
  743.                     if ((cp = strchr (atbbs, '.')) != NULLCHAR)
  744.                         *cp = '\0';    /* cut "atbbs" at first dot */
  745.                 }
  746.                 break;
  747.             case MSGID:
  748.                 if (!foundmid)    {
  749.                     foundmid = 1;
  750.                     trimrightCR (buf);
  751.                     bid[0] = '$';
  752.                     foundbid = makeBBSbid (&bid[1], LINELEN - 1, buf);
  753.                     /* if a bulletin and not in the history file, add it */
  754.                     if (*bul && !msgidcheck (&bid[1]))
  755.                         bid_add (&bid[1], time ((time_t *)0), 1, m->area);
  756.                 }
  757.                 break;
  758.             case SUBJECT:
  759.                 trimrightCR (buf);
  760.                 if (subj != NULLCHAR) {
  761.                     if (buf[8] != '\n')
  762.                         (void) grabtext (buf + 9, subj, '\n', LINELEN - 1);
  763.                     /* Make sure subject isn't empty - WG7J */
  764.                     cp = subj;
  765.                     while (*cp == ' ' || *cp == '\t')
  766.                         cp++;
  767.                     if (*cp == '\0')
  768.                         strcpy (subj, "None");
  769.                 }
  770.                 break;
  771.             case FROM:
  772.                 trimrightCR (buf);
  773.                 if ((cp = getaddress (buf, 0)) != NULLCHAR) {
  774.                     if (!strnicmp (cp, "REQSVR", 6) || !strnicmp (cp, "MAILER-DAEMON", 13)) {    /* MAILER-DAEMON going out->call sign */
  775.                         (void) pax25 (buf, Mycall);
  776.                         cp = strpbrk (buf, DIGI_IDS);
  777.                         if (cp)
  778.                             *cp = 0;
  779.                         strncpy (from, buf, LINELEN);
  780.                     } else
  781.                         (void) findident (cp, 1, from);    /* cp points to from@domain */
  782.                     from[ALEN] = '\0';    /* 6 character limit */
  783.                 }
  784.                 break;
  785.             case XFORWARD:
  786.                 if ((cp = getaddress (buf, 0)) == NULLCHAR)
  787.                     break;
  788.                 if (stricmp (m->name, cp) == 0) {
  789.  
  790.                     /* This message was RECEIVED from this BBS, abort */
  791.                     return -2;
  792.                 }
  793.                 break;
  794.             case BBSTYPE:
  795.                 if (m->stype == 'P') {
  796.                     /* we do not make messages in public areas into personals
  797.                      * but the reverse is permitted
  798.                      */
  799.                     m->stype = buf[16];
  800.                     if (m->stype == 'B')
  801.                         bulletin = *bul = 1;
  802.                     else
  803.                         bulletin = *bul = 0;
  804.                 }
  805.                 break;
  806.             default:
  807.                 break;
  808.         }
  809.     }
  810.     /* Check for an invalid RFC-822 header */
  811.     if ((to[0] == '\0' && ((dest != NULLCHAR && *dest == '\0') ||
  812.                    dest == NULLCHAR)) || from[0] == '\0')
  813.         return -2;
  814.  
  815. #ifdef STRICT_CALL
  816.     if (PBBSstrict && strcasecmp(from, "WP") && !iscall (from))
  817.         return -2;
  818. #endif
  819.  
  820.     if (line != NULLCHAR) {
  821. #ifdef FBBFWD
  822.         if (Mfbb && (m->sid & MBX_FBBFWD)) {
  823.             if (*atbbs)    {
  824.                 strncpy (tmp, atbbs, 39);
  825.                 tmp[39] = 0;
  826.             } else if (*m->call) {
  827.                 /* outgoing, we canNOT be sure m->name is correct!
  828.                    The BBS name in forward.bbs (which is m->name)
  829.                    does NOT need to be the BBS name, so we look at
  830.                    the callsign, instead... */
  831.                 (void) pax25 (tmp, m->call);
  832.                 if ((cp = strpbrk (tmp, DIGI_IDS)) != NULLCHAR)
  833.                     *cp = 0;
  834.             } else {
  835.                 strncpy (tmp, m->name, 39);
  836.                 tmp[39] = 0;
  837.             }
  838.         }
  839. #endif
  840.         if (dest != NULLCHAR && *dest != '\0') {
  841.             char *tempcp = strdup (dest);
  842.  
  843.             /* strip off hierarchical routing designators from the predefined
  844.              * destination address if they are not supported
  845.              */
  846. #ifdef FBBFWD
  847.             if (Mfbb && (m->sid & MBX_FBBFWD)) {
  848.                 if ((cp = strchr (tempcp, '.')) != NULLCHAR)
  849.                     *cp = '\0';
  850.                 if ((cp = strchr (tempcp, '@')) != NULLCHAR)
  851.                     *cp = '\0';
  852.                 sprintf (line, "FA %c %s %s %s ", m->stype, from, (cp) ? (cp + 1) : tmp, tempcp);
  853.             } else {
  854. #endif
  855.                 if ((m->sid & MBX_HIER_SID) == 0 && (cp = strchr (tempcp, '.')) != NULLCHAR)
  856.                     *cp = '\0';
  857.                 sprintf (line, "S%c %s < %s ", m->stype, tempcp, from);
  858. #ifdef FBBFWD
  859.             }
  860. #endif
  861.             free (tempcp);
  862.         } else {
  863. #ifdef FBBFWD
  864.             if (Mfbb && (m->sid & MBX_FBBFWD))
  865.                 sprintf (line, "FA %c %s %s %s ", m->stype, from, tmp, to);
  866.             else
  867. #endif
  868.                 sprintf (line, "S%c %s%s%s < %s ", m->stype, to, (*atbbs) ? " @ " : "", atbbs, from);
  869.         }
  870. #ifdef nope
  871.         /* This fixes the problem with personal MIDs being the same with
  872.          * messages generated from aliases, RMAIL, or mail-groups. Changes
  873.          * the bid from $abcde_host.domain to $abcde_destinationuser. - KO4KS
  874.          */
  875.         if (!bulletin && (m->sid & MBX_MID)) {
  876.             if ((cp = strrchr (bid, '_')) != NULLCHAR) {
  877.                 *cp++;
  878.                 if (!strnicmp (Hostname, cp, strlen (cp))) {
  879.                     *(cp - 1) = '%';
  880.                     if (dest != NULLCHAR && *dest != '\0')
  881.                         strcpy (cp, dest);
  882.                     else
  883.                         strcpy (cp, to);
  884.                     bid[13] = '\0';
  885.                     if ((cp = strchr (bid, '.')) != NULLCHAR)
  886.                         *cp = '\0';
  887.                 }
  888.             }
  889.         }
  890. #endif
  891.  
  892.         /* This keeps us from adding a MID to someone else's message */
  893.         if (!foundbid) {/* if one wasn't found, but GENERATED */
  894.             (void) fgets (buf, sizeof (buf), m->mfile);    /* get first data line */
  895.             if (!strnicmp (buf, "R:", 2))    /* if it has at least one "R:" line */
  896.                 bid[0] = '\0';    /* blank out the MID */
  897.         }
  898.         /* convert the bid to upper case for compatability with BBSs */
  899.         (void) strupr (bid);
  900.  
  901.         /* Add the bid to bulletins,
  902.          * AND ALSO to anything that came in with a bid !
  903.          * Takes care off duplicate 'SP SYSOP@xxx $BID' problems - WG7J
  904.          * ALSO add it to ALL messages if the remote system supports MID's - WG7J
  905.          */
  906. #ifdef FBBFWD
  907.         if (Mfbb && (m->sid & MBX_FBBFWD) &&
  908.             ((m->sid & MBX_MID) || (bulletin && (m->sid & MBX_SID))))
  909.             /* Append BID ( minus the '$' character. */
  910.             strcat (line, &bid[1]);
  911.         else
  912. #endif
  913.             /*    if((m->sid & MBX_MID) || ((bulletin || foundbid) & (m->sid & MBX_SID))) */
  914.         if ((m->sid & MBX_MID) || (bulletin && (m->sid & MBX_SID)))
  915.             strcat (line, bid);
  916. #ifdef FBBFWD
  917.         if (Mfbb && (m->sid & MBX_FBBFWD)) {
  918.             strcat (line, " ");
  919.             strcat (line, (char *) ltoa (m->mbox[msgn].size, bid2, 10));
  920.         }
  921. #endif
  922.         strcat (line, "\n");
  923.     }
  924.     return 0;
  925. }
  926.  
  927.  
  928.  
  929. static int            /* 0 = ok, -1 = problem so disc */
  930. sendmsgtobbs (m, msgn, dest, bulletin)
  931. struct mbx *m;
  932. int msgn;
  933. char const *dest;        /* Optional destination address to override To: line */
  934. int bulletin;
  935. {
  936. int result = -1;
  937. char line[LINELEN], subj[LINELEN], thebid[LINELEN];
  938.  
  939.     if (makecl (m, msgn, dest, line, subj, thebid, &bulletin) < 0)
  940.         return 0;    /* do not forward this particular message */
  941.  
  942.     if (thebid[0] == 0)    {
  943.         if (Mtrace)
  944.             tcmdprintf ("FWD: Skipping message to %s without a BID: %s\n", fwd_bbsname (m), line);
  945.         log (m->user, "Skipping message to %s without a BID: %s\n", fwd_bbsname (m), line);
  946.         return 0;
  947.     }
  948.     if (Mtrace)
  949.         tcmdprintf ("FWD: Sending to %s - %s.\n", fwd_bbsname (m), line);
  950.  
  951. #ifdef BBSEXPORT
  952.     if (m->quickfile) {
  953.         fputs (line, m->quickfile);
  954.         m->line[0] = 'O';
  955.     } else {
  956. #endif
  957.         tputs (line);    /* Send mail offer to bbs */
  958.         usflush (m->user);
  959. #ifdef BBSEXPORT
  960.     }
  961. #endif
  962.     rip (line);
  963.     if (m->quickfile || recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1) {
  964.         if (Mtrace)
  965.             tcmdprintf ("FWD: Received from %s - %s.\n", fwd_bbsname (m), m->line);
  966.  
  967.         if (m->line[0] == 'O' || m->line[0] == 'o' || (m->sid & MBX_SID) == 0) {
  968.             if (Mtrace)
  969.                 tcmdprintf ("FWD: Sending message to %s\n", fwd_bbsname (m));
  970.             /* Got 'OK' or any line if the bbs is unsofisticated */
  971. #ifdef BBSEXPORT
  972.             if (m->quickfile)
  973.                 fprintf (m->quickfile, "%s\n", subj);
  974.             else
  975. #endif
  976.                 tprintf ("%s\n", subj);
  977.             sendmsg (m, msgn, &thebid[1]);    /* send the message */
  978. #ifdef BBSEXPORT
  979.             if (m->quickfile) {
  980.                 fputs ("/EX\n", m->quickfile);
  981.                 strcpy (m->line, "> ");
  982.             } else {
  983. #endif
  984.                 if (FWDctlz)
  985.                     tputs ("\032\n");
  986.                 else
  987.                     tputs ("/EX\n");
  988.                 usflush (m->user);
  989. #ifdef BBSEXPORT
  990.             }
  991. #endif
  992.             /* get '>' for a good deliver */
  993.             while (m->quickfile || recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1)
  994.                 if (ISPROMPT (m->line)) {
  995.                     log (m->user, mailsent, line);
  996.                     if (!bulletin && (stricmp (m->area, "sysop") || !SYSOPprotect)) {
  997.                         m->mbox[msgn].status |= BM_DELETE;
  998.                         statusCtl (m->area, "ctl", &m->mbox[msgn], msgn, 0);
  999.                         m->change |= CHG_DELETE;
  1000.                     }
  1001.                     result = 0;
  1002.                     MbForwarded++;
  1003.                     break;
  1004.                 }
  1005.         } else {    /* OK response not received from bbs */
  1006.             if (tolower (m->line[0]) == 'n' || tolower (m->line[0]) == 'r') {    /* 'NO/REJECT' response */
  1007.                 log (m->user, mailrefused, line, m->line);
  1008.                 result = 0;    /* don't want it, so skip it! */
  1009.             } else
  1010.                 log (m->user, unexpectedresponse, line, m->line);
  1011.  
  1012.             /* should get a F> here */
  1013.             while (recvline (m->user, (unsigned char *) m->line, MBXLINE) != -1)
  1014.                 if (ISPROMPT (m->line)) {
  1015.                     result = 0;
  1016.                     break;
  1017.                 }
  1018.         }
  1019.     }            /* OK or NO here */
  1020.     if (m->stype != 'B')
  1021.         bid_delete (&thebid[1]);
  1022.     return result;
  1023. }
  1024.  
  1025.  
  1026.  
  1027. void
  1028. mark_forwarded (FILE *fp, long ind, char thetype)
  1029. {
  1030. long save;
  1031.  
  1032.     clearerr (fp);
  1033.     save = ftell (fp);
  1034.     fseek (fp, ind, SEEK_SET);
  1035.     fputc (thetype, fp);    /* mark as done! */
  1036.     (void) fflush (fp);
  1037.     fseek (fp, save, SEEK_SET);
  1038. }
  1039.  
  1040.  
  1041.  
  1042. /* Forward messages from one message area.  */
  1043. static int
  1044. fwdthisarea (struct mbx *m, FILE *fwd, char *area, char *newto)
  1045. {
  1046. int bulletin;
  1047. long bid, pos = 0;
  1048. int theindex, changed = 0, i;
  1049. int err = 0;
  1050. char *cp;
  1051. struct let *cmsg;
  1052. char line[80];
  1053.  
  1054.  
  1055.     kwait (NULL);
  1056.     bulletin = isarea (area);    /* public area */
  1057.  
  1058.     if (Mtrace && FWDareatrace)
  1059.         tcmdprintf ("FWD: Processing %s message area %s for %s.\n",
  1060.             bulletin ? "Public  " : "Private ", area, fwd_bbsname (m));
  1061.  
  1062.     if (bulletin && (!FWDbulletins || !m->fwdbbs->bulletins))
  1063.         return err;
  1064.     if (!bulletin && (!FWDpersonal || !m->fwdbbs->personals))
  1065.         return err;
  1066.     rewind (fwd);
  1067.     while (!err && fgets (line, sizeof (line), fwd) != NULLCHAR) {
  1068.         (void) fflush (fwd);
  1069.         kwait (NULL);
  1070.         if (*line == ' ') {    /* if not already done or blocked */
  1071.             if ((cp = strpbrk (&line[1], " \t")) == NULLCHAR)
  1072.                 continue;
  1073.             *cp++ = '\0';
  1074.             if (!stricmp (area, &line[1])) {    /* only if for us */
  1075.                 bid = atol (cp);
  1076.                 if (!changed) {    /* if not already changed */
  1077.                     m->area[0] = 0;           /* force a reload of index      */
  1078.                     changearea (m, area, (int) 1);
  1079.                     changed = 1;
  1080.                 }
  1081.                 theindex = 0;
  1082.                 for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
  1083.                     if ((bid == cmsg->bid) && !(cmsg->status & BM_DELETE)) {
  1084.                         theindex = i;
  1085.                         break;
  1086.                     }
  1087.                 if (theindex && m->fwdbbs && m->fwdbbs->maxsize && cmsg->size > m->fwdbbs->maxsize) {
  1088.                     if (Mtrace)
  1089.                         tcmdprintf (defering, m->fwdbbs->name, m->fwdbbs->maxsize, cmsg->size);
  1090.                 } else {
  1091.                     if (theindex && !(cmsg->status & (BM_ONHOLD | BM_DELETE))) {
  1092.                         mark_forwarded (fwd, pos, '!');
  1093.                         if (sendmsgtobbs (m, theindex, newto, bulletin) == -1)
  1094.                             err = 1;    /* abort */
  1095.                         else {
  1096. #ifdef STATS_MSG
  1097.                             STATS_addmsg (1, 1);
  1098. #endif
  1099. #ifdef STATS_TFC
  1100.                             STATS_addtfc (3, 1);
  1101. #endif
  1102. #ifdef STATS_FWD
  1103.                             STATS_addfwd (1, 1, m->name);
  1104. #endif
  1105.                         }
  1106.                     }
  1107.                     if (!theindex || (!err && !(cmsg->status & BM_ONHOLD)))
  1108.                         mark_forwarded (fwd, pos, '*');
  1109.                 }
  1110.             }
  1111.         }
  1112.         pos = ftell (fwd);    /* get new backup position */
  1113.         if (MBXMaintMode && MBXMaint)
  1114.             break;
  1115.     }
  1116.     return err;
  1117. }
  1118.  
  1119.  
  1120.  
  1121. /* This is the main entry point for reverse forwarding. It is also used
  1122.  * for normal, "forward", forwarding.
  1123.  */
  1124. int
  1125. dorevfwd (int argc OPTIONAL, char *argv[] OPTIONAL, void *p)
  1126. {
  1127. char oldarea[64], *area, *cp;
  1128. struct mbx *m;
  1129. int err = 0;
  1130. FILE *fwd;
  1131. long thesize, theend, newsize;
  1132. char name[256];
  1133. struct arealist *a;
  1134.  
  1135.     m = (struct mbx *) p;
  1136.     /* indicate we are doing reverse forwarding, if we are not already
  1137.      * doing normal forwarding.
  1138.      */
  1139.     if (m->state != MBX_FORWARD) {
  1140.         if (!FWDreverse)
  1141.             goto notallowed;
  1142.         m->state = MBX_REVFWD;
  1143.         if ((m->sid & MBX_SID) && m->mysize)
  1144.             smtptick (NULL);    /* wake SMTP to send that mail */
  1145.         m->mysize = 0;
  1146.     }
  1147.     if (m->fwdbbs || fwdinit (m, 1) != -1) {
  1148.         strncpy (oldarea, m->area, 64);
  1149.         sprintf (name, "%s/%s", Mailspool, m->name);
  1150.         (void) nntp_name_expansion (name);
  1151.         strcat (name, ".fwd");
  1152.         (void) strlwr (name);
  1153.         if ((fwd = fopen (name, UPDATE_TEXT)) == NULLFILE)
  1154.             return 0;    /* shouldn't happen except with reverse fwd */
  1155.         log (m->user, forwardingmailto, (m->state == MBX_REVFWD) ? "reverse " : "", m->name);
  1156.         thesize = (long) filelength (fileno (fwd));    /* so we know if any new */
  1157.  
  1158.         a = m->fwdbbs->areas;
  1159.         if (m->fwdbbs->noreverseincoming)
  1160.             m->usecolor = 0;
  1161.         if (m->state != MBX_FORWARD)
  1162.             if (checksubchannel (m, 1))
  1163.                 err = 1;
  1164.  
  1165.         while (!err) {
  1166.             if (cutofffwding (m))
  1167.                 break;
  1168.             if (m->privs & EXCLUDED_CMD)
  1169.                 break;
  1170.             newsize = (long) filelength (fileno (fwd));
  1171.             if (thesize != newsize) {
  1172.                 /* if new mail came in to forward, start back
  1173.                    up at the top of the areas to forward.
  1174.                    This allows you to push personal traffic
  1175.                    at highest priority */
  1176.                 thesize = newsize;
  1177.                 a = m->fwdbbs->areas;
  1178.             }
  1179.             if (a == NULLAREALIST)
  1180.                 break;
  1181.  
  1182.             cp = strdup ((a->forceaddr) ? a->forceaddr : "");
  1183.             area = strdup (a->name);
  1184.             a = a->next;
  1185.             err = fwdthisarea (m, fwd, area, cp);
  1186.             if (MBXMaintMode && MBXMaint)
  1187.                 break;
  1188.             free (cp);
  1189.             free (area);
  1190.         }
  1191.  
  1192.         if (*oldarea != '\0')
  1193.             changearea (m, oldarea, (int) 1);
  1194.         fwdlockit (m->name);
  1195.         theend = (long) filelength (fileno (fwd));
  1196.         if (!err && thesize == theend) {
  1197.             rewind (fwd);
  1198.             while (newsize = ftell (fwd), fgets (m->line, MBXLINE, fwd) != NULLCHAR) {
  1199.                 kwait (NULL);
  1200.                 if (*m->line == '=') {
  1201.                     mark_forwarded (fwd, newsize, '!');
  1202.                     err = 1;
  1203.                 } else if (*m->line == '!') {
  1204.                     mark_forwarded (fwd, newsize, ' ');
  1205.                     err = 1;
  1206.                 } else if (*m->line != '*' && *m->line != '-') {    /* if not already done */
  1207.                     err = 1;
  1208. #if 0
  1209.                     break;
  1210. #endif
  1211.                 }
  1212.             }
  1213.             (void) fclose (fwd);
  1214.             if (!err)
  1215.                 (void) remove (name);
  1216.         } else
  1217.             (void) fclose (fwd);
  1218.         fwdunlockit (m->name);
  1219.     }
  1220.     if (m->state != MBX_FORWARD)
  1221.         releasesubchannel (m);
  1222.     if (m->state == MBX_FORWARD)
  1223.         return err;
  1224. notallowed:
  1225.     /* This section marks the last fwd session time */
  1226.     if ((err = indexFwdBbs (fwd_bbsname (m))) != NUMFWDBBS) {
  1227.         MyFwds[err].laston = time (NULL);
  1228.         MyFwds[err].lastactivity = time (NULL);
  1229.     }
  1230.     tputs ("*** Done\n");
  1231.     tflush ();
  1232.     if (m->sid & MBX_RLI_SID)    /* disconnect if it is a W0RLI bbs */
  1233.         return domboxbye (0, NULL, m);
  1234.     return 0;
  1235. }
  1236.  
  1237.  
  1238.  
  1239. void
  1240. releasesubchannel (struct mbx *m)
  1241. {
  1242.     if (m->subchannel != NOSUBCHANNEL) {
  1243.         if (subchannels[m->subchannel].used)
  1244.             subchannels[m->subchannel].used--;
  1245.         m->subchannel = NOSUBCHANNEL;
  1246.     }
  1247. }
  1248.  
  1249.  
  1250.  
  1251. /* Check to see if there is room in the subchannel tables for this BBS,
  1252.  * *IF* they are suppose to use a subchannel. This routine also is used
  1253.  * to assign the subchannel, if desired. Returns 0 if subchannel is available,
  1254.  * -1 if it is NOT available.
  1255.  */
  1256. int
  1257. checksubchannel (struct mbx *m, int assignit)
  1258. {
  1259. int i;
  1260.  
  1261.     i = m->fwdbbs->subchannel;
  1262.  
  1263.     /* return OK if no subchannel is to be used */
  1264.     if (i == NOSUBCHANNEL)
  1265.         return 0;
  1266.  
  1267.     /* return OK if subchannel already assigned to this BBS */
  1268.     if (i == m->subchannel)
  1269.         return 0;
  1270.  
  1271.     /* Now check if there is room on this subchannel */
  1272.     if (i > NUMMBX || subchannels[i].used >= (int) subchannels[i].limit)
  1273.         return -1;    /* nope */
  1274.  
  1275.     /* Now we assign the subchannel slot to this BBS, if desired */
  1276.     if (assignit) {
  1277.         subchannels[i].used++;
  1278.         m->subchannel = i;
  1279.     }
  1280.     return 0;
  1281. }
  1282.  
  1283.  
  1284.  
  1285. static int
  1286. uselessconnect (struct mbx *m, char *filename)
  1287. {
  1288. int retval = -1;
  1289. FILE *fp;
  1290. char buf[255], *cp;
  1291. int foundone = 0, i;
  1292. long bid;
  1293. struct let *cmsg;
  1294. int anyvalid = 0;
  1295.  
  1296.     if (!access (filename, 0)) {
  1297.         if ((fp = fopen (filename, "r")) != NULLFILE)    {
  1298.             while (fgets (buf, 255, fp)) {
  1299.                 /* if forwarded, skip it (no valid message, here) */
  1300.                 if (*buf == '*')
  1301.                     continue;
  1302.  
  1303.                 /* if passed to an alt, skip it (valid message, though) */
  1304.                 if (*buf == '-')    {
  1305.                     anyvalid = 1;
  1306.                     continue;
  1307.                 }
  1308.  
  1309.                 if ((cp = strchr (&buf[1], ' ')) == NULLCHAR)
  1310.                     continue;    /* syntax error */
  1311.                 *cp++ = 0;
  1312.                 /* get internal id number of message */
  1313.                 bid = atol (cp);
  1314.                 changearea (m, &buf[1], (int) 0);
  1315.                 for (cmsg = &m->mbox[1], i = 1; i <= m->nmsgs; i++, cmsg++)
  1316.                     /* find the message we're supposed to forward. */
  1317.                     if (bid == cmsg->bid)    {
  1318.                         if (!(cmsg->status & (BM_DELETE | BM_ONHOLD))) {
  1319.                             /* this is the message... set the flag and break. */
  1320.                             foundone = 1;
  1321.                             break;
  1322.                         } else if (!(cmsg->status & BM_DELETE))    {
  1323.                             /* not deleted, just on hold (valid message) */
  1324.                             anyvalid = 1;
  1325.                         }
  1326.                     }
  1327.                 if (foundone) {
  1328.                     retval = 0;
  1329.                     break;
  1330.                 }
  1331.             }
  1332.             (void) fclose (fp);
  1333.         }
  1334.         if (!foundone)    {
  1335.             if (Mtrace)
  1336.                 tcmdprintf ("fwd: no available traffic found - skipping useless connect to %s\n", m->fwdbbs->name);
  1337.             if (!anyvalid)    {
  1338.                 /* if all messages are fwded or deleted, then remove the file */
  1339.                 (void) remove (filename);
  1340.                 if (Mtrace)
  1341.                     tcmdprintf ("fwd: no remaining traffic found - removing forward file for %s\n", m->fwdbbs->name);
  1342.             }
  1343.         }
  1344.     }
  1345.     return retval;
  1346. }
  1347.  
  1348.  
  1349.  
  1350. /* Read the forward file for a record for the connected BBS. If found,
  1351.  * return 0 if this is the right time to forward, m->tfile is left pointing
  1352.  * at the first message area to be forwarded.
  1353.  * returns -1, also, if nothing queued for forwarding.
  1354.  */
  1355. int
  1356. fwdinit (struct mbx *m, int try)
  1357. {
  1358. int retval = -1;
  1359. char name[256];
  1360.  
  1361.     fwdfree (&m->fwdbbs);
  1362.     m->fwdbbs = fwdread (m->name, try);
  1363.     if (m->fwdbbs != NULLFWDBBS && m->fwdbbs->conn) {
  1364.         sprintf (name, "%s/%s", Mailspool, m->fwdbbs->name);
  1365.         (void) nntp_name_expansion (name);
  1366.         strcat (name, ".fwd");
  1367.         (void) strlwr (name);
  1368.         if (m->special || m->fwdbbs->poll)
  1369.             retval = 0;
  1370.         else
  1371.             retval = uselessconnect (m, name);
  1372.     }
  1373.     if (!retval)
  1374.         retval = checksubchannel (m, 0);
  1375.     return retval;
  1376. }
  1377.  
  1378.  
  1379.  
  1380. /* Read the forward file for a record for the connected BBS. If found,
  1381.  * determine if this is the right time to forward, and return the command
  1382.  * line to establish a forwarding connection. m->tfile is left pointing
  1383.  * at the first message area to be forwarded.
  1384.  */
  1385. static int
  1386. fwdanybbs (struct mbx *m, int *poll, int *theindex)
  1387. {
  1388. int k;
  1389. int done = 0;
  1390. int retval = 0;
  1391.  
  1392.     *poll = 0;        /* Default to no polling */
  1393.  
  1394.     fwdfree (&m->fwdbbs);
  1395.  
  1396.     do {
  1397.         m->fwdbbs = fwdread (NULLCHAR, *theindex++);
  1398.         if (m->fwdbbs == NULLFWDBBS) {
  1399.             done = 1;
  1400.             continue;
  1401.         }
  1402.         if (!m->fwdbbs->conn) {    /* bad time - no connect method */
  1403.             if (Mtrace)
  1404.                 tcmdprintf ("fwd: skipping '%s' - no connect method\n", m->fwdbbs->name);
  1405.             /* This section keeps a inactive BBS from blocking others in a subchannel */
  1406.             k = indexFwdBbs (m->fwdbbs->name);
  1407.             if (k != NUMFWDBBS)
  1408.                 MyFwds[k].processed = 1;
  1409.             fwdfree (&m->fwdbbs);
  1410.             continue;
  1411.         }
  1412.         strncpy (m->name, m->fwdbbs->name, 20);
  1413.         *poll = m->fwdbbs->poll;
  1414.         if (m->special)
  1415.             *poll = 1;
  1416.         retval = 1;
  1417.         done = 1;
  1418.  
  1419.     } while (!done);
  1420.     return retval;
  1421. }
  1422.  
  1423.  
  1424.  
  1425. int
  1426. dombtimer (int argc, char *argv[], void *p OPTIONAL)
  1427. {
  1428.     if (argc < 2) {
  1429.         tprintf (forwardingtimer, read_timer (&fwdtimer) / 1000L, dur_timer (&fwdtimer) / 1000L);
  1430.         return 0;
  1431.     }
  1432.     stop_timer (&fwdtimer);    /* just in case */
  1433.     fwdtimer.func = (void (*)(void *)) fwdtick;    /* what to call on timeout */
  1434.     fwdtimer.arg = NULL;    /* dummy value */
  1435.     set_timer (&fwdtimer, atol (argv[1]) * 1000L);    /* set timer duration */
  1436.     start_detached_timer (&fwdtimer);/* fire it up */
  1437.     return 0;
  1438. }
  1439.  
  1440.  
  1441.  
  1442. int
  1443. dombkick (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  1444. {
  1445.     fwdtick (NULL);
  1446.     return 0;
  1447. }
  1448.  
  1449.  
  1450.  
  1451. /* MDMII: fwdproc is the old fwdtick.   But, since it can call kpause, which is
  1452.  * very very bad for timer functions :-( this has been converted to a server.
  1453.  */
  1454. static void
  1455. fwdtick (void *v OPTIONAL)
  1456. {
  1457.     start_detached_timer (&fwdtimer);/* and restart the timer */
  1458.     checkforALTs ();
  1459.     (void) forwardreset (0, 0, 0);
  1460.     if (FWDmode)
  1461.         if (newproc ("forward daemon", 2048, fwdproc, 0, NULL, NULL, 0) == NULLPROC)
  1462.             log (-1, nostart);
  1463. }
  1464.  
  1465.  
  1466.  
  1467. static void
  1468. checkoneALT (char *name)
  1469. {
  1470. long bid, pos = 0;
  1471. struct fwdbbs *f;
  1472. struct arealist *a;
  1473. struct altlist *alt;
  1474. char buf[256], *cp;
  1475. FILE *fp;
  1476. time_t now, then;
  1477. long size;
  1478. int nummsgs;
  1479.  
  1480.     (void) time (&now);
  1481.     f = fwdread (name, 1);
  1482.     if (f == NULLFWDBBS)    /* shouldn't happen */
  1483.         return;
  1484.  
  1485.     /* look at each area for this bbs */
  1486.     for (a = f->areas; a; a = a->next) {
  1487.  
  1488.         /* if there are no alternates for this area, skip it */
  1489.         if (!a->alternates)
  1490.             continue;
  1491.  
  1492.         /* now check to see if the *.fwd file exists */
  1493.         sprintf (buf, "%s/%s", Mailspool, f->name);
  1494.         (void) nntp_name_expansion (buf);
  1495.         strcat (buf, ".fwd");
  1496.         (void) strlwr (buf);
  1497.         if ((fp = fopen (buf, UPDATE_TEXT)) == NULLFILE)
  1498.             continue;    /* nope, skip it */
  1499.  
  1500.         nummsgs = 0;
  1501.         /* check every message not already forwarded or sent to an alt */
  1502.         while (pos = ftell (fp), fgets (buf, 255, fp)) {
  1503.             /* if forwarded or passed to an alt, skip it */
  1504.             if (*buf == '*' || *buf == '-')
  1505.                 continue;
  1506.             /* if not this area, skip it */
  1507.             if (strnicmp (&buf[1], a->name, strlen (a->name))) {
  1508.                 nummsgs++;
  1509.                 continue;
  1510.             }
  1511.             if ((cp = strchr (&buf[1], ' ')) == NULLCHAR)
  1512.                 continue;    /* syntax error */
  1513.             /* get internal id number of message */
  1514.             bid = atol (++cp);
  1515.             if ((cp = strchr (cp, ' ')) == NULLCHAR)
  1516.                 continue;    /* syntax error */
  1517.             /* get original timestamp */
  1518.             then = atol (++cp);
  1519.             if ((cp = strchr (cp, ' ')) == NULLCHAR)
  1520.                 continue;    /* syntax error */
  1521.             /* get original timestamp */
  1522.             size = atol (++cp);
  1523.             for (alt = a->alternates; alt; alt = alt->next) {
  1524.                 /* time to send to this alt? */
  1525.                 if ((then + (alt->minutes * 60)) > now) {
  1526.                     nummsgs++;
  1527.                     continue;    /* nope */
  1528.                 }
  1529.                 /* send it to the alt bbs's .fwd file */
  1530.                 updateFwd (alt->name, a->name, bid, size);
  1531.                 mark_forwarded (fp, pos, '-');
  1532.                 if (Mtrace)
  1533.                     tcmdprintf (queueing, bid, f->name, alt->name);
  1534.                 log (-1, queueing, bid, f->name, alt->name);
  1535.             }
  1536.         }
  1537.         (void) fclose (fp);
  1538.         if (!nummsgs) {
  1539.             sprintf (buf, "%s/%s", Mailspool, f->name);
  1540.             (void) nntp_name_expansion (buf);
  1541.             strcat (buf, ".fwd");
  1542.             (void) strlwr (buf);
  1543.             (void) remove (buf);
  1544.         }
  1545.     }
  1546.     fwdfree (&f);
  1547. }
  1548.  
  1549.  
  1550.  
  1551. void
  1552. checkforALTs (void)
  1553. {
  1554. int k;
  1555.  
  1556.     ReadFwdBbs ();        /* just in case */
  1557.  
  1558.     /* for each BBS in the forward.bbs file */
  1559.     for (k = 0; k < Numfwds; k++)
  1560.         checkoneALT (MyFwds[k].name);
  1561.  
  1562.     freeareas ();
  1563. }
  1564.  
  1565.  
  1566.  
  1567. int
  1568. forwardreset (int argc OPTIONAL, char *argv[] OPTIONAL, void *p OPTIONAL)
  1569. {
  1570. int k;
  1571.  
  1572.     for (k = 0; k < NUMFWDBBS; k++)
  1573.         MyFwds[k].processed = 0;
  1574.     return 0;
  1575. }
  1576.  
  1577.  
  1578.  
  1579. /* called when the forward timer expires or explicitly by dombkick() */
  1580. void
  1581. fwdproc (int nerf, void *v1, void *v2 OPTIONAL)
  1582. {
  1583. struct mbx *m;
  1584. int poll, k;
  1585. char name[256];
  1586. time_t t;
  1587. int doneit = 0;
  1588. char *bbsname = NULLCHAR;
  1589. int bbsindex = 0;
  1590. int skip;
  1591.  
  1592.     if (MBXMaintMode && MBXMaint) {
  1593.         if (Mtrace)
  1594.             tcmdprintf (delayedmaintenance);
  1595.         return;
  1596.     }
  1597.     if (v1)
  1598.         bbsname = strdup (v1);
  1599.     if (Mtrace)
  1600.         tcmdprintf (started);
  1601.     if ((m = newmbx (1)) == NULLMBX) {
  1602.         if (Mtrace)
  1603.             tcmdprintf (unabletostart);
  1604.         return;
  1605.     }
  1606.     (void) time (&t);
  1607.     m->special = (char) nerf;    /* non-zero, if forced or exported connect */
  1608.     m->logontime = (long) t;
  1609.     m->user = Curproc->output;
  1610.     m->name[0] = 0;
  1611.     m->state = MBX_TRYING;
  1612.     lastSessionSkipped = 0;
  1613.     while (fwdanybbs (m, &poll, &bbsindex)) {
  1614.         bbsindex++;
  1615.  
  1616.         if (Mtrace)
  1617.             tcmdprintf (examining, m->name);
  1618.         kwait (NULL);
  1619.         if (isconnbbs (m)) {
  1620.             /* already connected to this BBS, skip it */
  1621.             if (Mtrace)
  1622.                 tcmdprintf (alreadyconnected, m->name);
  1623.             goto skipped;
  1624.         }
  1625.         kwait (NULL);
  1626.         if (bbsname && stricmp (m->name, bbsname))
  1627.             goto skipped;
  1628.  
  1629.         /* If we poll, there is no need to check message area, since this
  1630.          * is also done later. It will speed things up here - WG7J
  1631.          */
  1632.         if (!poll) {    /* don't need if polling */
  1633.             sprintf (name, "%s/%s.fwd", Mailspool, m->name);
  1634.             (void) strlwr (name);
  1635.             if (Mtrace)
  1636.                 tcmdprintf (checkingforfile, name);
  1637.         }
  1638.         skip = 0;
  1639.         k = indexFwdBbs (m->name);
  1640. #if 1
  1641.         if (!m->special && m->fwdbbs->minidle && k != NUMFWDBBS && MyFwds[k].lastactivity && (MyFwds[k].lastactivity + (time_t) m->fwdbbs->minidle) > t)
  1642.             skip = 1;
  1643. #endif
  1644.         /* This section keeps a dead BBS from blocking other in a subchannel */
  1645.         if (poll || !uselessconnect (m, name)) {
  1646.             if (checksubchannel (m, 0)) {    /* maxed out */
  1647.                 lastSessionSkipped = 1;
  1648.                 goto skipped;
  1649.             }
  1650.             if (k != NUMFWDBBS) {
  1651.                 if (MyFwds[k].processed) {
  1652. #if 0
  1653.                     int chk;
  1654.  
  1655.                     for (chk = 0; chk < NUMFWDBBS; chk++) {
  1656.                         if (MyFwds[k].subchannel == MyFwds[chk].subchannel && MyFwds[chk].processed == 0)
  1657. #endif
  1658.                             goto skipped;
  1659. #if 0
  1660.                     }
  1661. #endif
  1662.                 } else
  1663.                     MyFwds[k].processed = 1;
  1664.             }
  1665.             if (!strnicmp (m->fwdbbs->conn, "incoming", strlen (m->fwdbbs->conn))) {
  1666.                 /* it is an incoming PBBS, only */
  1667.                 if (Mtrace)
  1668.                     tcmdprintf ("fwd: skipping incoming-only: %s\n", m->name);
  1669.                 goto skipped;
  1670.             }
  1671.             if (skip || checksubchannel (m, 1))
  1672.                 goto skipped;
  1673.  
  1674.             if (Mtrace)
  1675.                 tcmdprintf ("fwd: to %s\n", m->name);
  1676.  
  1677.             sprintf (m->line, "PBBS forwarding: %s", m->name);
  1678.             (void) newproc (m->line, 3072, startfwd, (int) m->subchannel | (m->special << 8), (void *) 0, (void *) strdup (m->name), 0); /*lint !e701 */
  1679.             m->subchannel = NOSUBCHANNEL;
  1680.             kwait (NULL);
  1681.         } else {
  1682.             /* not polling and we have nothing, mark us as done */
  1683.             if (k != NUMFWDBBS)
  1684.                 MyFwds[k].processed = 1;
  1685.         }
  1686.         if (nerf) {
  1687.             doneit = 1;
  1688.             break;
  1689.         }
  1690.           skipped:if (nerf && doneit)
  1691.             break;
  1692.     }
  1693.     m->state = MBX_FORWARD;
  1694.     if (lastSessionSkipped == 0)
  1695.         (void) forwardreset (0, NULLCHARP, 0);
  1696.     if (bbsname)
  1697.         free (bbsname);
  1698.     exitbbs (m);
  1699. }
  1700.  
  1701.  
  1702.  
  1703. /* returns 1 if m->name matches the name of another connected mailbox. */
  1704. static int
  1705. isconnbbs (struct mbx *m)
  1706. {
  1707. int i;
  1708.  
  1709.     for (i = 0; i < NUMMBX; ++i)
  1710.         if (Mbox[i] != NULLMBX && Mbox[i] != m &&
  1711.             (stricmp (m->name, Mbox[i]->name) == 0) &&
  1712.             (Mbox[i]->sid & MBX_SID))
  1713.             return 1;
  1714.     return 0;
  1715. }
  1716.  
  1717.  
  1718.  
  1719. /* code to support setting the time of TNC PMS's that request it */
  1720. static int
  1721. fwd_clockset (struct mbx *m)
  1722. {
  1723. time_t now;
  1724. struct tm *t;
  1725.  
  1726.     if ((m->sid & MBX_CLOCK) && (!m->fwdbbs->noclockset)) {
  1727.         /* send the clock set command to the TNC */
  1728.         now = time ((time_t *) 0);
  1729.         now += (((long) m->fwdbbs->clockoffset) * 3600L);
  1730.         t = localtime (&now);
  1731.         usprintf (m->user, "C %02d%02d%02d %02d%02d\n", t->tm_year,
  1732.               t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min);
  1733.         usflush (m->user);
  1734.         for (;;) {
  1735.             if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1)
  1736.                 return -1;
  1737.             if (ISPROMPT (m->line))
  1738.                 break;
  1739.         }
  1740.     }
  1741.     return 0;
  1742. }
  1743.  
  1744.  
  1745.  
  1746. /* possible commands on the command line in the forwarding file */
  1747. static struct cmds cfwdcmds[] =
  1748. {
  1749. #ifdef AX25
  1750.     { "ax25",    openconn,    0, 0, NULLCHAR },
  1751.     { "connect",    openconn,    0, 0, NULLCHAR },
  1752. #endif
  1753. #ifdef BBSEXPORT
  1754.     { "export",    openconn,    0, 0, NULLCHAR },
  1755. #endif
  1756.     { "fbbtelnet",    openconn,    0, 0, NULLCHAR },
  1757.     { "incoming",    openconn,    0, 0, NULLCHAR },
  1758. #ifdef NETROM
  1759.     { "netrom",    openconn,    0, 0, NULLCHAR },
  1760. #endif
  1761.     { "tcp",    openconn,    0, 0, NULLCHAR },
  1762.     { "telnet",    openconn,    0, 0, NULLCHAR },
  1763.     { NULLCHAR,    NULL,        0, 0, NULLCHAR }
  1764. };
  1765.  
  1766.  
  1767.  
  1768. static void
  1769. fwdcleanup (struct mbx *m, const char *string)
  1770. {
  1771. int k;
  1772. char *thisname;
  1773.  
  1774.     thisname = fwd_bbsname (m);
  1775.     if (Mtrace && string)
  1776.         tcmdprintf (string, thisname);
  1777.     log (-1, (string) ? string : forwardingcomplete, thisname);
  1778.  
  1779.     /* This section marks the last fwd session time */
  1780.     k = indexFwdBbs (thisname);
  1781.     if (k != NUMFWDBBS) {
  1782.         if (m->sid & MBX_SENTSID || m->fwdbbs->alwaysupdate)    {
  1783.             MyFwds[k].laston = time (NULL);
  1784.             smtptick(NULL);        /* kick the smtp server, just in case */
  1785.         }
  1786.         MyFwds[k].lastactivity = time (NULL);
  1787.     }
  1788.     releasesubchannel (m);
  1789.     exitbbs (m);
  1790.     if (lastSessionSkipped)
  1791.         fwdtick (NULL);
  1792. }
  1793.  
  1794.  
  1795.  
  1796.  
  1797. /* this function tells us whether the forwarding session has
  1798.    gone too long */
  1799. int
  1800. cutofffwding (struct mbx *m)
  1801. {
  1802. time_t now;
  1803.  
  1804.     /* if not initialized, or limittime disabled, return okay */
  1805.     if (!m || m->quickfile || !m->fwdbbs || !m->fwdbbs->limittime)
  1806.         return 0;
  1807.  
  1808.     /* if no starttime (incoming session), initialize it, and return okay */
  1809.     if (m->fwdbbs->starttime)    {
  1810.         (void) time (&m->fwdbbs->starttime);
  1811.         return 0;
  1812.     }
  1813.  
  1814.     /* else, get current time, and see if limittime reached */
  1815.     (void) time (&now);
  1816.     if ((now - m->fwdbbs->starttime) > m->fwdbbs->limittime)
  1817.         return 1;
  1818.     else
  1819.         return 0;
  1820. }
  1821.  
  1822.  
  1823.  
  1824. /* this function is called whenever the forwarding timer expires */
  1825. static void
  1826. startfwd (int a, void *v1 OPTIONAL, void *v2)
  1827. {
  1828. struct mbx *m;
  1829. int32 timeout;
  1830. int rval, retval;
  1831. time_t t;
  1832. int poll;
  1833. struct fscript *s;
  1834. int connectnum = 1;
  1835. int err;
  1836. char export[7];
  1837. #ifdef LOCK
  1838. int lockedstate;
  1839. #endif
  1840.  
  1841.     server_disconnect_io ();
  1842.     poll = a / 256;
  1843.     a %= 256;
  1844.     if ((m = newmbx (1)) == NULLMBX) {
  1845.         free ((char *) v2);
  1846.         if (a != NOSUBCHANNEL)
  1847.             subchannels[a].used--;
  1848.         return;
  1849.     }
  1850.     m->subchannel = a;
  1851. #ifdef STATS_USE
  1852.     STATS_adduse (0);
  1853. #endif
  1854.     (void) time (&t);
  1855.     m->special = (char) ((poll == 1) ? poll : 0);
  1856.     m->logontime = (long) t;
  1857.     strncpy (m->name, (char *) v2, 20);
  1858.  
  1859.     strcpy (export, "export");
  1860.  
  1861.     free ((char *) v2);
  1862.     m->state = MBX_TRYING;
  1863.     for (;;) {
  1864.         fwdfree (&m->fwdbbs);
  1865.         m->fwdbbs = fwdread (m->name, connectnum);
  1866.         if (m->fwdbbs->conn == NULLCHAR) {    /* shouldn't happen */
  1867.             fwdcleanup (m, "fwd: error in forward.bbs for %s\n");
  1868.             return;
  1869.         }
  1870.         if (poll == 1 && !stricmp (m->fwdbbs->conn, export))
  1871.             poll = 2;
  1872.         if (Mtrace)
  1873.             tcmdprintf ("fwd: Attempting connect #%d to %s: '%s'\n", connectnum, m->name, (poll == 2) ? export : m->fwdbbs->conn);
  1874.  
  1875. #ifdef LOCK
  1876.         lockedstate = Kblocked;
  1877.         Kblocked = 0;
  1878. #endif
  1879.         /* open the connection, m->user will be the new socket */
  1880.         retval = cmdparse (cfwdcmds, (poll == 2) ? export : m->fwdbbs->conn, (void *) m);
  1881. #ifdef LOCK
  1882.         Kblocked = lockedstate;
  1883. #endif
  1884.         if (retval != -1)
  1885.             break;
  1886.  
  1887.         if (connectnum++ == m->fwdbbs->maxtries) {
  1888.             checkoneALT (m->name);
  1889.             fwdcleanup (m, "fwd: unknown connect protocol or TRIES exceeded to %s\n");
  1890.             return;
  1891.         }
  1892.         if (Mtrace)
  1893.             tcmdprintf (connectionfailed, m->name, connectnum - 1);
  1894.     }
  1895.     m->state = MBX_FORWARD;
  1896.     if (m->user)
  1897.         (void) sockowner (m->user, Curproc);
  1898.     close_s (Curproc->output);
  1899.     close_s (Curproc->input);
  1900.     /* m->user will be closed automatically when this process exits */
  1901.     Curproc->output = Curproc->input = m->user;
  1902.     /* We'll do our own flushing right before we read input */
  1903.     kwait (NULL);
  1904. #ifdef BBSEXPORT
  1905.     if (m->user)
  1906. #endif
  1907.         (void) setflush (m->user, -1);
  1908.  
  1909. #if 0
  1910.     if (fwdinit (m, connectnum) == -1) {
  1911.         /* it is probably not the right time to forward anymore */
  1912.         fwdcleanup (m, NULLCHAR);
  1913.         return;
  1914.     }
  1915. #endif
  1916. #ifdef BBSEXPORT
  1917.     if (!m->user) {
  1918.         m->sid = (MBX_SID | MBX_MID | MBX_HIER_SID);
  1919. #if 0
  1920.         if (!m->special)
  1921. #endif
  1922.             (void) dorevfwd (0, NULL, (void *) m);
  1923.         (void) fclose (m->quickfile);
  1924.         fwdcleanup (m, NULLCHAR);
  1925.         close_s (Curproc->output);
  1926.         return;
  1927.     }
  1928. #endif
  1929.  
  1930.     /* read the connect script. Lines starting with a dot will be sent
  1931.      * to the remote BBS.
  1932.      */
  1933.     for (s = m->fwdbbs->script; s; s = s->next) {
  1934.         if (s->linetype == SCRIPT_SID) {
  1935.             strncpy (m->line, s->string, 20);
  1936.             (void) mbx_parse (m);    /* interpret it */
  1937.             /* now automatically send OUR SID */
  1938. #ifdef MBFWD
  1939.             mbx_SendSid (m);
  1940. #endif
  1941.             continue;
  1942.         }
  1943.         if (s->linetype == SCRIPT_SEND) {
  1944.             tprintf (s->string);
  1945.             tputc ('\n');
  1946.             if (Mtrace)
  1947.                 tcmdprintf ("fwd: %s > %s\n", m->name, s->string);
  1948.         } else if (s->linetype == SCRIPT_WAIT) {
  1949.             char good[80], bad[80], *myptr;
  1950.             int checkbad = 0;
  1951.  
  1952.             bad[0] = 0;
  1953.             strncpy (good, s->string, 80);
  1954.             if ((myptr = strchr (good, '|')) != NULLCHAR) {
  1955.                 /* negative search string found */
  1956.                 *myptr++ = 0;
  1957.                 strncpy (bad, myptr, 80);
  1958.                 checkbad = 1;
  1959.             }
  1960.             timeout = s->timeout;
  1961.             if (timeout)    /* if a valid conversion */
  1962.                 timeout *= 1000;    /* in ms ! */
  1963.             if (Mtrace)
  1964.                 tcmdprintf ("fwd: %s, wait %d < %s\n", m->name, s->timeout, s->string);
  1965.  
  1966.             /* Now do the actual response interpretations */
  1967.             kalarm (timeout);
  1968.             for (;;) {
  1969.  
  1970.                 rval = recvline (m->user, (unsigned char *) m->line, MBXLINE);
  1971.                 if (Mtrace) {
  1972.                     tcmdprintf ("fwd: %s, rx %d", m->name, rval);
  1973.                     if (rval >= 0)
  1974.                         tcmdprintf (", %s", m->line);
  1975.                     else
  1976.                         tcmdprintf ("\n");
  1977.                 }
  1978.                 /* Did we timeout, or connection disappear ? */
  1979.                 if (rval < 0) {
  1980.                     fwdcleanup (m, "fwd: %s, aborted!\n");
  1981.                     return;
  1982.                 }
  1983.                 if (strstr (m->line, good))
  1984.                     break;
  1985.                 if (checkbad && strstr (m->line, bad)) {
  1986.                     fwdcleanup (m, "fwd: %s, aborted!\n");
  1987.                     return;
  1988.                 }
  1989.             }
  1990.             kalarm (0L);
  1991.         } else        /* must be the end of the script */
  1992.             goto go_on;
  1993.  
  1994.         usflush (m->user);    /* send it, if any */
  1995.     }
  1996.     /* Now we've past all in-between stuff, go talk to the bbs ! */
  1997. go_on:
  1998.     usflush (m->user);
  1999.     if (Mtrace)
  2000.         tcmdprintf (scriptdone, m->name);
  2001.  
  2002.     /* read the initial output from the bbs, looking for the SID */
  2003.     for (;;) {
  2004.         timeout = 120 * 1000L;    /* wait up to 2 minutes for each response line */
  2005.         if (Mtrace)
  2006.             tcmdprintf (waitingfor, m->name, timeout / 1000, ">");
  2007.         kalarm (timeout);
  2008.         rval = recvline (m->user, (unsigned char *) m->line, MBXLINE);
  2009.         kalarm (0L);
  2010.         if (rval == -1) {
  2011.             fwdcleanup (m, NULLCHAR);
  2012.             return;
  2013.         }
  2014.         if (Mtrace)
  2015.             tcmdprintf ("fwd: %s < %s", m->name, m->line);
  2016.         if (ISPROMPT (m->line))
  2017.             break;
  2018.         if (*m->line == '[') {    /* parse the SID */
  2019.             rip (m->line);
  2020.             (void) mbx_parse (m);
  2021.             continue;
  2022.         }
  2023.     }
  2024.  
  2025.     /* Now sync the two ends as telnet password messes them up */
  2026.     if (socklen (m->user, 0))    /* discard any remaining input */
  2027.         (void) recv_mbuf (m->user, NULL, 0, NULLCHAR, 0);
  2028.  
  2029.     /* set the start time, for cutofffwding() */
  2030.     (void) time (&m->fwdbbs->starttime);
  2031.  
  2032.     /* send our SID if the peer announced its SID */
  2033. #ifdef FBBFWD
  2034.     if (Mfbb && (m->sid & MBX_FBBFWD)) {
  2035.         /* All we do is send a SID and start forwarding. */
  2036.         /* The remote box doesn't send any OK prompts.   */
  2037.  
  2038.         /* Send [xxxx] string. */
  2039.         mbx_SendSid (m);
  2040.         if (!(m->sid & MBX_FBBFWD))    /* since mbx_SendSid can change this */
  2041.             goto adjust;
  2042.         if (fwd_clockset (m) != -1)
  2043.             /* start the actual forwarding */
  2044.             (void) dofbbfwd (0, NULL, (void *) m);
  2045.         fwdcleanup (m, NULLCHAR);
  2046.         return;
  2047.     } else
  2048. #endif
  2049.     if (m->sid & MBX_SID) {
  2050.         mbx_SendSid (m);
  2051. #ifdef FBBFWD
  2052. adjust:
  2053. #endif
  2054.         if (fwd_clockset (m) == -1) {
  2055.             fwdcleanup (m, NULLCHAR);
  2056.             return;
  2057.         }
  2058.         usflush (m->user);
  2059.         for (;;) {
  2060.             if (recvline (m->user, (unsigned char *) m->line, MBXLINE) == -1) {
  2061.                 fwdcleanup (m, NULLCHAR);
  2062.                 return;
  2063.             }
  2064.             if (ISPROMPT (m->line))
  2065.                 break;
  2066.         }
  2067.     } else    {
  2068.         /* if the sysop has told us that this is a dumb PMS, then
  2069.            we will ignore the lack of a SID */
  2070.         if (!m->fwdbbs->dumbpms)    {
  2071.             /* if we get here and have NOT received a SID, we have a
  2072.                screwed up forwarding script, or the remote has a SERIOUS
  2073.                breach of the forwarding protocol. Since we do NOT know the
  2074.                capabilities of the remote machine, we abort! */
  2075.             log (m->user, nosidfound, fwd_bbsname(m));
  2076.             log (m->user, nosidfound2);
  2077.             tcmdprintf (nosidfound, fwd_bbsname(m));
  2078.             tcmdprintf ("\n");
  2079.             tcmdprintf (nosidfound2);
  2080.             tcmdprintf ("\n");
  2081.             fwdcleanup (m, NULLCHAR);
  2082.             return;
  2083.         }
  2084.     }
  2085.         
  2086.     /* start the actual forwarding */
  2087. #ifdef FBBFWD
  2088.     if (Mfbb && (m->sid & MBX_FBBFWD)) {
  2089.         (void) dofbbfwd (0, NULL, (void *) m);
  2090.         fwdcleanup (m, NULLCHAR);
  2091.         return;
  2092.     } else
  2093. #endif
  2094. #ifdef XFWD
  2095.     if (MXfwd && (m->sid & MBX_XFWD)) {
  2096.         (void) doxfwd (0, NULL, (void *) m);
  2097.         fwdcleanup (m, NULLCHAR);
  2098.         return;
  2099.     } else
  2100. #endif
  2101.         m->usecolor = (char) FWDinreverse;    /* default to this, each entry can override */
  2102.     err = dorevfwd (0, NULL, (void *) m);
  2103.     /* if no incoming reverse, just disconnect, else */
  2104.     /* ask for reverse forwarding or just disconnect */
  2105.     if (err || m->usecolor == 0 || ((m->sid & MBX_SID) && tputs ("F>\n") == -1) ||
  2106.         (m->sid & MBX_SID) == 0) {
  2107.         fwdcleanup (m, NULLCHAR);
  2108.         close_s (Curproc->output);
  2109.         return;
  2110.     }
  2111.     m->usecolor = 0;
  2112.     usflush (m->user);
  2113.     /* parse the commands that are are received during reverse
  2114.      * forwarding.
  2115.      */
  2116.     while (recvline (m->user, (unsigned char *) m->line, MBXLINE) > 0) {
  2117.         if (cutofffwding (m))
  2118.             break;
  2119.         if (m->privs & EXCLUDED_CMD)
  2120.             break;
  2121.         rip (m->line);
  2122.         if ((rval = mbx_parse (m)) < 0)
  2123.             /* -2 == "*** Done" rec'd, -1 => cmd not in Mbcmds, or other err) */
  2124.             break;
  2125.         if (rval && BBSdump)    /* we dump for all unknowns! */
  2126.             break;
  2127.         if (m->privs & EXCLUDED_CMD)
  2128.             break;
  2129.         if (MBXMaintMode && MBXMaint)
  2130.             break;
  2131.         tputs ("F>\n");
  2132.         usflush (m->user);
  2133.     }
  2134.     (void) domboxbye (0, NULL, m);
  2135.  
  2136.     if ((m->sid & MBX_SID) && m->mysize)
  2137.         smtptick (NULL);/* wake SMTP to send that mail */
  2138.     fwdcleanup (m, NULLCHAR);
  2139.     usflush (Curproc->output);
  2140.     kpause (500L);
  2141.     close_s (Curproc->output);
  2142. }
  2143.  
  2144.  
  2145.  
  2146. /* open a network connection based upon information in the cc line.
  2147.  * m->user is set to the socket number.
  2148.  */
  2149. static int
  2150. openconn (int argc, char *argv[], void *p)
  2151. {
  2152. struct mbx *m;
  2153. char sock[MAXSOCKSIZE];
  2154. union sp sp;
  2155. int len;
  2156. #ifdef NETROM
  2157. char alias[AXBUF];
  2158. struct nrroute_tab *rp;
  2159. #endif
  2160. #ifdef BBSEXPORT
  2161. char namebuf[512];
  2162. #endif
  2163.  
  2164.     m = (struct mbx *) p;
  2165.     sp.p = sock;
  2166. #ifdef BBSEXPORT
  2167.     if (argv[0][0] != 'e' && argc < 2)
  2168. #else
  2169.     if (argc < 2)
  2170. #endif
  2171.         return -1;
  2172.     switch (*argv[0]) {
  2173.         case 'f':
  2174.             m->fwdbbs->limittype &= ~FWDTYPE_XFWD;
  2175.             /* fall through */
  2176.         case 't':
  2177.             sp.in->sin_family = AF_INET;
  2178.             {
  2179.                 if ((sp.in->sin_addr.s_addr = resolve (argv[1])) == 0)
  2180.                     return -1;
  2181.                 /* get the optional port number */
  2182.                 if (argc > 2)
  2183.                     sp.in->sin_port = (int16) atoip (argv[2]);
  2184.                 else
  2185.                     sp.in->sin_port = IPPORT_TELNET;
  2186.             }
  2187.             if ((m->user = socket (AF_INET, SOCK_STREAM, 0)) == -1)
  2188.                 return -1;
  2189.             len = sizeof (*sp.in);
  2190.             m->family = AF_INET;    /*So the user list will be correct! - WG7J */
  2191.             break;
  2192. #ifdef AX25
  2193.         case 'a':
  2194.         case 'c':    /* allow 'c' for 'connect' as well */
  2195.             if (argc < 3)
  2196.                 return -1;
  2197.             sp.ax->sax_family = AF_AX25;
  2198.             if (if_lookup (argv[1]) == NULLIF) {
  2199.                 if (Mtrace)
  2200.                     tcmdprintf (badax25iface, argv[1], m->name);
  2201.                 log (-1, badax25iface, argv[1], m->name);
  2202.                 return -1;
  2203.             }
  2204.             if ((m->user = socket (AF_AX25, SOCK_STREAM, 0)) == -1)
  2205.                 return -1;
  2206.             if (*FWDCall) {
  2207.                 memcpy (sp.ax->ax25_addr, FWDCall, AXALEN);
  2208.                 (void) bind (m->user, (char *) sp.ax, sizeof (struct sockaddr_ax));
  2209.             }
  2210.             strncpy (sp.ax->iface, argv[1], ILEN - 1);    /* the interface name */
  2211.             (void) setcall (sp.ax->ax25_addr, argv[2]);    /* the remote callsign */
  2212.  
  2213.             /* no digipeaters for now, use the "ax25 route add" command */
  2214.             /* this code attempts to correct this longstanding limitation */
  2215.             if (argc > 3) {
  2216.                 int didrose = 0, i;
  2217.                 char tmp[AXBUF];
  2218.  
  2219.                 if (!strcmp (argv[3], "@")) {
  2220.                     didrose = 1;
  2221.                     argv[3] = strdup (pax25 (tmp, AXRosecall));
  2222.                 }
  2223.                 i = connect_filt (argc, argv, sp.ax->ax25_addr, if_lookup (argv[1]), AX_SETUP);
  2224.                 if (didrose)
  2225.                     free (argv[3]);
  2226.                 if (i == 0)
  2227.                     return -1;
  2228.             }
  2229.             len = sizeof (*sp.ax);
  2230.             m->family = AF_AX25;    /*So the user list will be correct! - WG7J */
  2231.             break;
  2232. #endif /* AX25 */
  2233. #ifdef NETROM
  2234.         case 'n':
  2235.             /* See if the requested destination could be an alias, and
  2236.              * use it if it is.  Otherwise assume it is an AX.25
  2237.              * address.
  2238.              */
  2239.             (void) putalias (alias, argv[1], 0);
  2240.             (void) strupr (argv[1]);
  2241.             if ((rp = find_nrboth (alias, argv[1])) == NULLNRRTAB) {
  2242.                 if (Mtrace)
  2243.                     tcmdprintf (Netromunavailable, argv[1]);
  2244.                 return -1;
  2245.             }
  2246.             /* Setup the local side of the connection */
  2247.             sp.nr->nr_family = AF_NETROM;
  2248.             len = sizeof (*sp.nr);
  2249.             if ((m->user = socket (AF_NETROM, SOCK_SEQPACKET, 0)) == -1) {
  2250.                 if (Mtrace)
  2251.                     tcmdprintf (Netromsocket, argv[1]);
  2252.  
  2253.                 return -1;
  2254.             }
  2255.             memcpy (sp.nr->nr_addr.user, Nr4user, AXALEN);
  2256.             memcpy (sp.nr->nr_addr.node, Nr_iface->hwaddr, AXALEN);
  2257.             (void) bind (m->user, sp.p, len);
  2258.  
  2259.             /* Now the remote side */
  2260.             memcpy (sp.nr->nr_addr.node, rp->call, AXALEN);
  2261.             /* The user callsign of the remote station is never
  2262.              * used by NET/ROM, but it is needed for the psocket() call.
  2263.              */
  2264.             memcpy (sp.nr->nr_addr.user, rp->call, AXALEN);
  2265.  
  2266.             m->family = AF_NETROM;    /*So the user list will be correct! - WG7J */
  2267.             break;
  2268. #endif /* NETROM */
  2269. #ifdef BBSEXPORT
  2270.         case 'e':
  2271.             /* open current export file */
  2272.             sprintf (namebuf, "%s/%s.exp", EXPORTDir, m->name);
  2273.             m->quickfile = fopen (namebuf, APPEND_TEXT);
  2274.             if (m->quickfile) {
  2275.                 m->user = 0;
  2276.                 m->family = AF_LOCAL;
  2277.                 return 0;
  2278.             }    /* else, fall through */
  2279. #endif
  2280.         case 'i':    /* incoming only, no outbound */
  2281.         default:
  2282.             return -1;
  2283.     }
  2284.     (void) sockmode (m->user, SOCK_ASCII);
  2285.     if (*argv[0] == 'f')
  2286.         (void) seteol (m->user, "\r\n");
  2287.  
  2288.     if (connect (m->user, sp.p, len) == -1) {
  2289.         log (m->user, forwardfailed, sockerr (m->user), errno);
  2290.         close_s (m->user);
  2291.         return -1;
  2292.     }
  2293.     return m->user;
  2294. }
  2295.  
  2296.  
  2297.  
  2298. void
  2299. forwardingSummary ()
  2300. {
  2301. int k, first = 1, i;
  2302. char curstate, curtype;
  2303. register FILE *fp;
  2304. char buf[100], *cp;
  2305. int totbul = 0, totper = 0, bul, per;
  2306. long size, totsize = 0;
  2307.  
  2308.     ReadFwdBbs ();        /* just in case */
  2309.     for (k = 0; k < Numfwds; k++) {
  2310.         sprintf (buf, "%s/%s.fwd", Mailspool, MyFwds[k].name);
  2311.         (void) strlwr (buf);
  2312.         per = bul = 0;
  2313.         size = 0;
  2314.         if ((fp = fopen (buf, READ_TEXT)) != NULLFILE) {
  2315.             while (fgets (buf, sizeof (buf), fp) != NULLCHAR)
  2316.                 if (*buf != '*' && *buf != '-') {
  2317.                     cp = strchr (&buf[1], ' ');
  2318.                     if (cp) {
  2319.                         *cp++ = 0;
  2320.                         if (isarea (&buf[1]))
  2321.                             bul++;
  2322.                         else
  2323.                             per++;
  2324.                         cp = strrchr (cp, ' ');
  2325.                         if (cp)
  2326.                             size += atol (++cp);
  2327.                     }
  2328.                 }
  2329.             (void) fclose (fp);
  2330.         }
  2331.         totsize += size;
  2332.         if (size)
  2333.             size = ((size + 513) / 1024);
  2334.         if (first) {
  2335.             tputc ('\n');
  2336.             first = 0;
  2337.         }
  2338.         curstate = ':';
  2339.         curtype = ' ';
  2340.         for (i = 0; i < NUMMBX; ++i) {
  2341.             if (Mbox[i] == NULLMBX)
  2342.                 continue;
  2343.             if (!stricmp (Mbox[i]->name, MyFwds[k].name) && Mbox[i]->state >= MBX_SUBJ && Mbox[i]->state <= MBX_FORWARD) {
  2344.                 curstate = '*';
  2345. #ifdef XFWD
  2346.                 if (MXfwd && Mbox[i]->sid & MBX_XFWD)
  2347.                     curtype = 'X';
  2348. #endif
  2349. #ifdef FBBFWD
  2350.                 if (Mfbb && Mbox[i]->sid & MBX_FBBFWD)
  2351.                     curtype = 'F';
  2352. #endif
  2353.                 break;
  2354.             }
  2355.         }
  2356.  
  2357.         tprintf ("Queued for forwarding to %-10.10s%c%c Bulletins/Personal (%5d/%-5d) %-ldK\n", MyFwds[k].name, curstate, curtype, bul, per, size);
  2358.         totbul += bul;
  2359.         totper += per;
  2360.     }
  2361.     if (k) {
  2362.         if (totsize)
  2363.             totsize = ((totsize + 513) / 1024);
  2364.         for (k = 0; k < 78; k++)
  2365.             tputc ('-');
  2366.         tprintf ("\nTotal messages to forward          :  Bulletins/Personal (%5d/%-5d) %-ldK\n\n", totbul, totper, totsize);
  2367.     } else
  2368.         tputs ("You have no BBS's in your 'forward.bbs' file!\n");
  2369. }
  2370.  
  2371.  
  2372.  
  2373. int
  2374. AREAlookup (char *area, int theindex)
  2375. {
  2376. int retval = 0;
  2377. struct fwdbbs *f = NULLFWDBBS;
  2378. struct arealist *a;
  2379. int cur = 0;
  2380.  
  2381.     for (cur = 0; cur <= theindex; cur++) {
  2382.         f = fwdread (NULLCHAR, cur);
  2383.         if (f == NULLFWDBBS)
  2384.             return retval;
  2385.         if (cur != theindex)
  2386.             fwdfree (&f);
  2387.     }
  2388.     if (f) {
  2389.         a = f->areas;
  2390.         while (a) {
  2391.             if (!stricmp (a->name, area)) {
  2392.                 retval = (!a->isALT);
  2393.                 break;
  2394.             }
  2395.             a = a->next;
  2396.         }
  2397.         fwdfree (&f);
  2398.     }
  2399.     return retval;
  2400. }
  2401.  
  2402. #endif /*MBFWD*/
  2403.  
  2404.  
  2405.  
  2406. void
  2407. fwdlockit (char *name)
  2408. {
  2409.     while (mlock (Mailspool, name))
  2410.         kpause (1000L);        /* Wait one second and try again */
  2411. }
  2412.  
  2413.  
  2414.  
  2415. void
  2416. fwdunlockit (char *name)
  2417. {
  2418.     rmlock (Mailspool, name);
  2419. }
  2420.